class ValuePair{ //存储原始值
    constructor(key,value) { //单个的字典值的节点
        this.key = key
        this.value = value
    }
    toString(){
        return `[${this.key}:${this.value}]` //单个值节点转成字符串
    }
}

class HashTable{
    constructor(){
        this.table = {}
    }

    toStringFN(item){ //形参item就等同于key意思
        if(item === null){ //如果传入的key是null
            return ""
        }else if(item === undefined){ //如果传入的是undefined
            return "Undefined"
        }else if(typeof item === "string" || item instanceof String){ //如果传入的是与字符串有关的
            return `${item}`
        }
        //当然这个方法不算完美，因为有些对象名可能天生带有_id，所以可以生成一个非常复杂的独一无二的id识别码来避免这种情况
        if(item["_id"]){ //判断是否是被我们改造过的重名对象，这行代码替换掉了下面的set中注释掉的更新tablekey
            return item.toString() + item["_id"]
        }
        //如果以上情况都不是
        return item.toString()
    }

    loseloseHASHCode(key){ //将key转换成string，但是这样也依旧会算出相同的数，所以还需要再借助分离链接法
        if(typeof key === "number"){
            return key
        }
        let tablekey = toStringFN(key)
        let hashCode = 0
        //hash算法非常多，这里用一种遍历其中每一个字符，然后累加每一个字符的字符编码charCodeAt
        for(let i = 0; i < tablekey.length; i++){
            hashCode += tablekey.charCodeAt(i)
        }
        return hashCode % 37 //质数求余，除以任意一个质数取余，将取得的余数作为key，
        //密码学中非常难生成所有质数，因为质数无法用通项公式生成，所以用质数比较难被破解
    }

    add(key,value){ //散列表增加值
        if(key != null && key != undefined){
            let position = this.loseloseHASHCode(key) //将哈希函数生成的索引赋值给下标position
            this.table[position] = new ValuePair(key,value)
            return true //添加成功
        }
        return false //添加失败
    }

    get(key){ //通过索引key获取对应值
        let position = this.loseloseHASHCode(key)
        return this.table[position]
        //return this.table[this.loseloseHASHCode(key)] 上面两行代码可以合成这一行
    }

    remove(key){ //通过索引key删除对应值
        let position = this.loseloseHASHCode(key)
        delete this.table[position]
    }
}